﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Casamiel.API.Application.Models;
using Casamiel.API.Application.Services;
using Casamiel.API.Infrastructure.Middlewares;
using Casamiel.Application;
using Casamiel.Common;
using Casamiel.Common.Extensions;
using Casamiel.Domain;
using Casamiel.Domain.Entity;
using Casamiel.Domain.Request;
using Casamiel.Domain.Response;
using Casamiel.Domain.Response.IC;
using Enyim.Caching;
using MediatR;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Casamiel.API.Application.Commands
{
    /// <summary>
    /// Get my card command handler.
    /// </summary>
    public sealed class GetMyCardCommandHandler : BaseCommandHandler, IRequestHandler<GetMyCardCommand, BaseResult<List<CardInfoResponse>>>
    {
        private readonly IMemcachedClient _memcachedClient;

        private readonly string _memcachedPre;
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Casamiel.API.Application.Commands.GetMyCardCommandHandler"/> class.
        /// </summary>
        /// <param name="memcachedClient"></param>
        /// <param name="snapshot"></param>
        /// <param name="iicApiService">Iic API service.</param>
        /// <param name="memberCard">Member card.</param>
        /// <param name="mobileCheckCode">Mobile check code.</param>
        /// <param name="userLogService">User log service.</param>
        /// <param name="memberService">Member service.</param>
        /// <param name="tokenProvider">Token provider.</param>
        public GetMyCardCommandHandler(IMemcachedClient memcachedClient, IOptionsSnapshot<CasamielSettings> snapshot, IIcApiService iicApiService,
          IMemberCardService memberCard,
            IMobileCheckCode mobileCheckCode, IUserLogService userLogService, IMemberService memberService, ITokenProvider tokenProvider) : base(iicApiService, memberCard, mobileCheckCode, memberService, userLogService, tokenProvider)
        {
            if (snapshot == null) {
                throw new ArgumentNullException(nameof(snapshot));
            }

            _memcachedClient = memcachedClient;
            _memcachedPre = snapshot.Value.MemcachedPre;
        }
        /// <summary>
        /// Handle the specified request and cancellationToken.
        /// </summary>
        /// <returns>The handle.</returns>
        /// <param name="request">Request.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        public async Task<BaseResult<List<CardInfoResponse>>> Handle(GetMyCardCommand request, CancellationToken cancellationToken)
        {
            if (request == null)
                throw new ArgumentNullException(nameof(request));
            string mobile = request.Mobile;
            var list = await MemberCardService.GetListAsync<ICasaMielSession>(mobile).ConfigureAwait(false);
            var memberInfo = await MemberService.FindAsync<ICasaMielSession>(request.Mobile).ConfigureAwait(false);

            var mycard = list.Where(a => a.IsBind == true && a.CardType != "4").ToList();
            List<CardInfoResponse> cardlist = new List<CardInfoResponse>();

             
            //if (mobile == "18605888772")
            //{
            var dic = new ConcurrentDictionary<string, CardInfoResponse>();
            // System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            
            ParallelLoopResult paralleresulr = Parallel.ForEach(mycard, card => {
                var zmodel = IcApiService.GetCardBalance(card.CardNO,$"{request.Source}099".ToInt32(0)).ConfigureAwait(false).GetAwaiter().GetResult();
                var rnt = JsonConvert.DeserializeObject<JObject>(zmodel.content);
                if (zmodel.code == 0) {
                    dic.TryAdd(card.CardNO, new CardInfoResponse {
                        cardno = card.CardNO,
                        totalmoney = rnt == null ? "0" : rnt["totalmoney"].ToString(),
                        cardtype = card.CardType,
                        state = $"{ card.State}",
                        othermoney = rnt == null ? "0" : rnt["othermoney"].ToString(),
                        directmoney = rnt == null ? "0" : rnt["directmoney"].ToString(),
                        point = rnt == null ? "0" : rnt["point"].ToString(),
                        Grade = rnt == null ? 0 : rnt["cardtype"].ToInt32(0),
                        Gradename= rnt == null ? "" :(rnt["cardtypename"]==null?"":rnt["cardtypename"].ToString()),
                    }); ;//, (key, oldValue) =>new CardInfoResponse ());
                } else if (zmodel.code == 90) {
                    var data = new CardRefreshRequest { Cardno = card.CardNO, Phoneno = mobile, Startdate = DateTime.Now.ToString("yyyy-MM-dd 00:00:00", CultureInfo.CurrentCulture) };
                    var zmdel = IcApiService.Icrefresh(data).ConfigureAwait(false).GetAwaiter().GetResult();
                    Logger.Trace($"CardRefresh:{JsonConvert.SerializeObject(zmdel)}");
                    if (zmdel.code == 0) {
                        var jcard = JsonConvert.DeserializeObject<JObject>(zmdel.content);
                        //var mcard = await _memberCard.FindAsyncByCardnoMobile<ICasaMielSession>(item.CardNo, mobile);
                        //var clist = await _memberCard.GetCardListAsyncByMobile<ICasaMielSession>(mobile).ConfigureAwait(false);
                        var c = card;
                        c.IsBind = false;
                        c.UnBindTime = DateTime.Now;
                        MemberCardService.UpdateAsync<ICasaMielSession>(c).ConfigureAwait(false).GetAwaiter().GetResult();
                        //var mcard = clist.Where(c => c.CardType == "1" && c.IsBind == true).SingleOrDefault();
                        //if (mcard != null)
                        //{
                        //    mcard.CardNo = jcard["newcardno"].ToString();
                        //    mcard.IsBind = false;
                        //    mcard.UnBindTime = DateTime.Now;
                        //    await _memberCard.UpdateAsync<ICasaMielSession>(mcard).ConfigureAwait(false);
                        //}
                        // mcard = await _memberCard.FindAsyncByCardnoMobile<ICasaMielSession>(jcard["newcardno"].ToString(), mobile).ConfigureAwait(false);
                        //if (mcard == null)
                        //{
                        var mcard = new MemberCard {
                            CardNO = jcard["newcardno"].ToString(),
                            Mobile = mobile,
                            IsBind = true,
                            CardType = "1",
                            M_ID = memberInfo.ID,
                            State = 1,
                            Source = request.Source,
                            BindTime = DateTime.Now,
                            CreateTime = DateTime.Now
                        };

                        var _cachekey = _memcachedPre + Constant.CARDREPLACEMENT + mcard.CardNO;
                        var trynum = _memcachedClient.Increment(_cachekey, 1, 1);
                        try {
                            if (trynum == 1) {
                                MemberCardService.AddAsync<ICasaMielSession>(mcard).ConfigureAwait(false).GetAwaiter().GetResult();
                                var logdata = new UserLog { Url = request.RequestUrl, OPInfo = $"补会员卡,原卡号:[{card.CardNO}，新卡号：{mcard.CardNO}", OPTime = DateTime.Now, UserName = mobile, UserIP = request.UserIP };
                                UserLogService.AddAsync<ICasaMielSession>(logdata).ConfigureAwait(false).GetAwaiter().GetResult();
                            }
                        } catch (SqlException ex) {
                            base.Logger.Error($"CardAddAsync:{ex.StackTrace}");
                            _memcachedClient.Remove(_cachekey);
                        }



                        var czmodel = IcApiService.GetCardBalance(mcard.CardNO, $"{request.Source}099".ToInt32(0)).ConfigureAwait(false).GetAwaiter().GetResult();
                        // _cacheService.Remove(Constant.MYCARDS_PREFIX + mobile);
                        if (czmodel.code == 0 || czmodel.code == 8) {
                            var cardinfo = JsonConvert.DeserializeObject<JObject>(czmodel.content);
                            dic.TryAdd(mcard.CardNO, new CardInfoResponse {
                                cardno = mcard.CardNO,
                                totalmoney = rnt == null ? "0" : cardinfo["totalmoney"].ToString(),
                                cardtype = card.CardType,
                                state = $"{card.State}",
                                othermoney = rnt == null ? "0" : cardinfo["othermoney"].ToString(),
                                directmoney = rnt == null ? "0" : cardinfo["directmoney"].ToString(),
                                point = rnt == null ? "0" : cardinfo["point"].ToString(),
                                Grade = rnt == null ? 0 : rnt["cardtype"].ToInt32(0),
                                Gradename = rnt == null ? "" : rnt["cardtypename"].ToString(),
                            });
                        }
                    }
                } else if (zmodel.code == 105)// || zmodel.code == 8)
                  {
                    card.IsBind = false;
                    MemberCardService.UpdateAsync<ICasaMielSession>(card).ConfigureAwait(false).GetAwaiter().GetResult();
                } else {
                    dic.TryAdd(card.CardNO, new CardInfoResponse {
                        cardno = card.CardNO,
                        state = $"{card.State}",
                        totalmoney = "0",
                        cardtype = card.CardType,
                        othermoney = "0",
                        directmoney = "0",
                        point = "0"
                    });
                }
            });

            foreach (var item in dic) {
                cardlist.Add(item.Value);
            }
            var result1 = new BaseResult<List<CardInfoResponse>>(cardlist, 0, "");
            return result1;


            // }

            for (int i = 0; i < mycard.Count; i++) {
                var zmodel = await IcApiService.GetCardBalance(mycard[i].CardNO, $"{request.Source}099".ToInt32(0)).ConfigureAwait(false);
                var rnt = JsonConvert.DeserializeObject<JObject>(zmodel.content);
                if (zmodel.code == 0) {
                    cardlist.Add(new CardInfoResponse {
                        cardno = mycard[i].CardNO,
                        totalmoney = rnt == null ? "0" : rnt["totalmoney"].ToString(),
                        cardtype = mycard[i].CardType,
                        state = $"{ mycard[i].State}",
                        othermoney = rnt == null ? "0" : rnt["othermoney"].ToString(),
                        directmoney = rnt == null ? "0" : rnt["directmoney"].ToString(),
                        point = rnt == null ? "0" : rnt["point"].ToString()
                    });
                } else if (zmodel.code == 90) {
                    var data = new CardRefreshRequest { Cardno = mycard[i].CardNO, Phoneno = mobile, Startdate = DateTime.Now.ToString("yyyy-MM-dd 00:00:00", CultureInfo.CurrentCulture) };
                    var zmdel = await IcApiService.Icrefresh(data).ConfigureAwait(false);
                    Logger.Trace($"CardRefresh:{JsonConvert.SerializeObject(zmdel)}");
                    if (zmdel.code == 0) {
                        var jcard = JsonConvert.DeserializeObject<JObject>(zmdel.content);
                        //var mcard = await _memberCard.FindAsyncByCardnoMobile<ICasaMielSession>(item.CardNo, mobile);
                        //var clist = await _memberCard.GetCardListAsyncByMobile<ICasaMielSession>(mobile).ConfigureAwait(false);
                        mycard[i].IsBind = false;
                        mycard[i].UnBindTime = DateTime.Now;
                        await MemberCardService.UpdateAsync<ICasaMielSession>(mycard[i]).ConfigureAwait(false);
                        //var mcard = clist.Where(c => c.CardType == "1" && c.IsBind == true).SingleOrDefault();
                        //if (mcard != null)
                        //{
                        //    mcard.CardNo = jcard["newcardno"].ToString();
                        //    mcard.IsBind = false;
                        //    mcard.UnBindTime = DateTime.Now;
                        //    await _memberCard.UpdateAsync<ICasaMielSession>(mcard).ConfigureAwait(false);
                        //}
                        // mcard = await _memberCard.FindAsyncByCardnoMobile<ICasaMielSession>(jcard["newcardno"].ToString(), mobile).ConfigureAwait(false);
                        //if (mcard == null)
                        //{
                        var mcard = new MemberCard {
                            CardNO = jcard["newcardno"].ToString(),
                            Mobile = mobile,
                            IsBind = true,
                            CardType = "1",
                            M_ID = memberInfo.ID,
                            State = 1,
                            Source = request.Source,
                            BindTime = DateTime.Now,
                            CreateTime = DateTime.Now
                        };

                        var _cachekey = _memcachedPre + Constant.CARDREPLACEMENT + mcard.CardNO;
                        var trynum = _memcachedClient.Increment(_cachekey, 1, 1);
                        try {
                            if (trynum == 1) {
                                await MemberCardService.AddAsync<ICasaMielSession>(mcard).ConfigureAwait(false);
                                var logdata = new UserLog { Url = request.RequestUrl, OPInfo = $"补会员卡,原卡号:[{mycard[i].CardNO}，新卡号：{mcard.CardNO}", OPTime = DateTime.Now, UserName = mobile, UserIP = request.UserIP };
                                await UserLogService.AddAsync<ICasaMielSession>(logdata).ConfigureAwait(false);
                            }
                        } catch (SqlException ex) {
                            base.Logger.Error($"CardAddAsync:{ex.StackTrace}");
                            _memcachedClient.Remove(_cachekey);
                        }



                        var czmodel = await IcApiService.GetCardBalance(mcard.CardNO, $"{request.Source}099".ToInt32(0)).ConfigureAwait(false);
                        // _cacheService.Remove(Constant.MYCARDS_PREFIX + mobile);
                        if (czmodel.code == 0 || czmodel.code == 8) {
                            var cardinfo = JsonConvert.DeserializeObject<JObject>(czmodel.content);
                            cardlist.Add(new CardInfoResponse {
                                cardno = mcard.CardNO,
                                totalmoney = rnt == null ? "0" : cardinfo["totalmoney"].ToString(),
                                cardtype = mycard[i].CardType,
                                state = $"{mycard[i].State}",
                                othermoney = rnt == null ? "0" : cardinfo["othermoney"].ToString(),
                                directmoney = rnt == null ? "0" : cardinfo["directmoney"].ToString(),
                                point = rnt == null ? "0" : cardinfo["point"].ToString()
                            });
                        }
                    }
                } else if (zmodel.code == 105)// || zmodel.code == 8)
                  {
                    mycard[i].IsBind = false;
                    await MemberCardService.UpdateAsync<ICasaMielSession>(mycard[i]).ConfigureAwait(false);
                } else {
                    cardlist.Add(new CardInfoResponse {
                        cardno = mycard[i].CardNO,
                        state = $"{mycard[i].State}",
                        totalmoney = "0",
                        cardtype = mycard[i].CardType,
                        othermoney = "0",
                        directmoney = "0",
                        point = "0"
                    });
                }
            }
            var result = new BaseResult<List<CardInfoResponse>>(cardlist, 0, "");
            return result;
        }
    }
}
